// http://en.wikipedia.org/wiki/Edge_detection
// http://en.wikipedia.org/wiki/Canny_edge_detector
// http://www.pages.drexel.edu/~weg22/can_tut.html
// http://www.cs.bham.ac.uk/research/projects/poplog/popvision/help/canny
// http://www.cs.uiowa.edu/~cwyman/classes/spring08-22C251/homework/canny.pdf
// http://www.kilometer0.com/edge_detection.php
// http://lukewalsh.co.uk/blog/2008/05/real-time-edge-detection-in-flash.html
// http://lukewalsh.co.uk/blog/2008/06/sobel-edge-detection-in-flash.html
// http://me.queensu.ca/people/sellens/research/sprayFlow/mcleod/research/imagepro.htm

package
{
	import flash.display.BitmapData;
	import flash.filters.ColorMatrixFilter;
	import flash.filters.ConvolutionFilter;
	import flash.geom.Point;
	
	public class MyBitmapData extends BitmapData{
		private var fillColor:uint;
		
		public function MyBitmapData(width:int, height:int, transparent:Boolean=true, fillColor:uint=0) {
			this.fillColor = fillColor;
			super(width, height, transparent, fillColor);
		} 
		
		//There are a number of different ways to convert a colour image to 
		// greyscale, it really doesn't matter which one we choose too much. 
		// A simple greyscale will be used. The average of the red, 
		// green and blue colour channels will be put on the blue colour 
		// channel, this will lead to a 'bluescale' image, which will be used 
		// for speed.
		public function bluescaleFilter():void {
			var grayscale:ColorMatrixFilter = new ColorMatrixFilter(
				[0,  0,  0,  0,  0, 
				 0,  0,  0,  0,  0, 
				 1/3, 1/3, 1/3, 0, 0, 
				 0, 0, 0, 1, 0]);
			this.applyFilter(this, this.rect,new Point(),grayscale);
		}
		
		private function myApplyFilter(matrix:Array, width:int, height:int, divisor:int, bias:int):void {
			var convolutionFilter:ConvolutionFilter = new ConvolutionFilter(width,height, matrix, divisor, bias); 
			this.applyFilter(this, this.rect, new Point(), convolutionFilter);
		}
		
		// The convolution filter is offset by 127 so that both positive 
		// (white to black) and negative (black to white) edge responses 
		// can be stored in the image.
		public function sobelFilterX():void {
			var convolutionMatrix:Array = [ -1,  0,  1,
							 				-2,  0,  2,
							  				-1,  0,  1 ];
			this.myApplyFilter(convolutionMatrix, 3, 3, 1, 127);
		}
		
		// The convolution filter is offset by 127 so that both positive 
		// (white to black) and negative (black to white) edge responses 
		// can be stored in the image.
		public function sobelFilterY():void {
			var convolutionMatrix:Array = [  1,  2,  1,
							 				 0,  0,  0,
							  				-1, -2, -1 ];
			this.myApplyFilter(convolutionMatrix, 3, 3, 1, 127);
		}
		
//		public function gradientMagnitudeFilter():void {
//			var snapshotDataX:MyBitmapData = this.clone().sobelFilterX( );
//			var snapshotDataY:MyBitmapData = this.clone().sobelFilterY( );
//			var pixel:int = 0;
//			var pixelX:int;
//			var pixelY:int;
//			var lowerThreshold:int = 0 + 120;
//			var upperThreshold:int = 0xff - 120;
//
//			for( var x:int = 0; x < this.width; x++) {
//        		for( var y:int = 0; y < this.height; y++ ) {
//					//Just using blue channel.
//        			pixelX = (snapshotDataX.getPixel(x,y) & 0xff);
//        			pixelY = (snapshotDataY.getPixel(x,y) & 0xff);
//        			// Check threshold
//        			if( !(pixelX > lowerThreshold && pixelX < upperThreshold && pixelY > lowerThreshold && pixelY < upperThreshold)){
//        				// The 127 offset is removed so that the edge responses 
//        				// are now positive and negative.
//        				pixelX = pixelX - 127;
//        				pixelY = pixelY - 127;
//        				pixel = Math.abs( pixelX ) + Math.abs( pixelY );
//        				// Minus one because otherwise max value is 256
//        				pixel = pixel - 1;
//        				pixel = (pixel << 16) + (pixel << 8) + pixel;
//        				snapshotData.setPixel( x, y, pixel);
//        			}else{
//        				snapshotData.setPixel( x, y, 0);
//        			}
//        		}
//   			}
//		}
		
		public function red():MyBitmapData {
			var bitmapData:MyBitmapData = new MyBitmapData(this.height, this.width, this.transparent, this.fillColor);
			for( var x:int = 0; x < this.width; x++)
        		for( var y:int = 0; y < this.height; y++ )
        			bitmapData.setPixel(x,y, this.getPixel(x,y) & 0x0000FF );
        	return bitmapData;
		}
		
		public function green():MyBitmapData {
			var bitmapData:MyBitmapData = new MyBitmapData(this.height, this.width, this.transparent, this.fillColor);
			for( var x:int = 0; x < this.width; x++)
        		for( var y:int = 0; y < this.height; y++ )
        			bitmapData.setPixel(x,y, (this.getPixel(x,y) & 0x00FF00) >> 8 );
        	return bitmapData;
		}
		
		public function blue():MyBitmapData {
			var bitmapData:MyBitmapData = new MyBitmapData(this.height, this.width, this.transparent, this.fillColor);
			for( var x:int = 0; x < this.width; x++)
        		for( var y:int = 0; y < this.height; y++ )
        			bitmapData.setPixel(x,y, (this.getPixel(x,y) & 0xFF0000) >> 16 );
        	return bitmapData;
		}
//		
//		public function merge(red:MyBitmapData, green:MyBitmapData, blue:MyBitmapData):MyBitmapData {
//			
//		}

//		public function clone():MyBitmapData {
//			return super.clone();
//		}
		
	}

}